﻿using System.Collections.Specialized;
using System.Web;
using System.Web.Routing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Web.Mvc;
using MvcSupplantCaching;

namespace MvcSupplantCaching.UnitTests
{
    [TestClass]
    public class KeyGeneratorTest : BaseTest
    {
        private KeyGenerator _generator;

        #region Test Strings

        const string VaryByCustom = "custom";
        const string VaryByCustomValue = "vary-by-value";
        const string VaryByParam = "page";
        const string ControllerName = "test";
        const string ActionName = "index";
        const string TestKey = "testkey";
        const string TestValue = "testval";

        #endregion

        [TestInitialize]
        public void Initialize()
        {
            _generator = new KeyGenerator(new KeyBuilder());
        }

        [TestMethod]
        public void GenerateKeyControllerTest()
        {
            CacheSettings settings = new CacheSettings
            {
                Duration = 300
            };

            var routeData = new RouteData();
            routeData.Values.Add("Controller", ControllerName);
            string key = _generator.GenerateKey(GetMockControllerContext(null, routeData).Object, settings);
            Assert.IsNull(key);
        }

        [TestMethod]
        public void GenerateKeyControllerActionTest()
        {
            CacheSettings settings = new CacheSettings
            {
                Duration = 300
            };

            var routeData = new RouteData();
            routeData.Values.Add("Controller", ControllerName);
            routeData.Values.Add("Action", ActionName);
            string key = _generator.GenerateKey(GetMockControllerContext(null, routeData).Object, settings);
            Assert.IsNotNull(key);
            Assert.AreNotEqual(string.Empty, key);
            Assert.IsTrue(key.Contains(ControllerName));
            Assert.IsTrue(key.Contains(ActionName));
        }

        [TestMethod]
        public void GenerateKeyVaryByParamTest()
        {
            CacheSettings settings = new CacheSettings
            {
                Duration = 300,
                VaryByParam = VaryByParam
            };

            var routeData = new RouteData();
            routeData.Values.Add("Controller", ControllerName);
            routeData.Values.Add("Action", ActionName);
            string key = _generator.GenerateKey(GetMockControllerContext(null, routeData).Object, settings);
            Assert.IsNotNull(key);
            Assert.AreNotEqual(string.Empty, key);
            Assert.IsTrue(key.Contains(ControllerName));
            Assert.IsTrue(key.Contains(ActionName));
            Assert.IsTrue(key.Contains(VaryByParam));
        }

        [TestMethod]
        public void GenerateKeyVaryByCustomTest()
        {
            CacheSettings settings = new CacheSettings
            {
                Duration = 300,
                VaryByCustom = VaryByCustom,
                VaryByParam = VaryByParam
            };

            var routeData = new RouteData();
            routeData.Values.Add("Controller", ControllerName);
            routeData.Values.Add("Action", ActionName);
            string key = _generator.GenerateKey(GetMockControllerContext(VaryByCustomValue, routeData).Object, settings);
            Assert.IsNotNull(key);
            Assert.AreNotEqual(string.Empty, key);
            Assert.IsTrue(key.Contains(ControllerName));
            Assert.IsTrue(key.Contains(ActionName));
            Assert.IsTrue(key.Contains(VaryByParam));
            Assert.IsTrue(key.Contains(VaryByCustom));
            Assert.IsTrue(key.Contains(VaryByCustomValue));
        }

        [TestMethod]
        public void GenerateKeyRouteValuesTest()
        {
            CacheSettings settings = new CacheSettings
            {
                Duration = 300,
                VaryByCustom = VaryByCustom,
                VaryByParam = VaryByParam
            };

            var routeData = new RouteData();
            routeData.Values.Add("Controller", ControllerName);
            routeData.Values.Add("Action", ActionName);
            routeData.Values.Add(TestKey, TestValue);
            string key = _generator.GenerateKey(GetMockControllerContext(VaryByCustomValue, routeData).Object, settings);
            Assert.IsNotNull(key);
            Assert.AreNotEqual(string.Empty, key);
            Assert.IsTrue(key.Contains(ControllerName));
            Assert.IsTrue(key.Contains(ActionName));
            Assert.IsTrue(key.Contains(VaryByParam));
            Assert.IsTrue(key.Contains(VaryByCustom));
            Assert.IsTrue(key.Contains(VaryByCustomValue));
            Assert.IsTrue(key.Contains(TestKey));
            Assert.IsTrue(key.Contains(TestValue));
        }

        [TestMethod]
        public void GenerateCacheKeyFromControllerTest()
        {
            CacheSettings settings = new CacheSettings
            {
                Duration = 300,
                VaryByCustom = VaryByCustom,
                VaryByParam = VaryByParam
            };


            var routeData = new RouteData();
            routeData.Values.Add("Controller", ControllerName);
            routeData.Values.Add("Action", ActionName);
            routeData.Values.Add(TestKey, TestValue);
            var mockControllerContext = GetMockControllerContext(VaryByCustomValue, routeData);
            string key = _generator.GenerateKey(mockControllerContext.Object, settings);

            var mockSupplantCacheAttribute = new Mock<ISupplantOutputCacheAttribute>();
            mockSupplantCacheAttribute.Setup(s => s.CacheSettings).Returns(settings);
            var actionExecutingContext = GetMockActionExecutingContext(VaryByCustomValue, routeData);
            actionExecutingContext.Setup(ctx => ctx.ActionDescriptor.GetCustomAttributes(typeof(ISupplantOutputCacheAttribute), true))
                                    .Returns(new object[] { mockSupplantCacheAttribute.Object });

            mockSupplantCacheAttribute.Setup(s => s.GetCacheKeyForController(actionExecutingContext.Object)).Returns(() => new KeyGenerator(new KeyBuilder()).GenerateKey(actionExecutingContext.Object, mockSupplantCacheAttribute.Object.CacheSettings));

            string key2 = actionExecutingContext.Object.GetOutputCacheKey();
            Assert.AreEqual(key, key2);
        }
    }
}
